package qq2564874169.tuaotuao.fx;

import qq2564874169.tuaotuao.fx.utils.ExUtil;
import qq2564874169.tuaotuao.fx.utils.UrlUtil;

import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
import java.io.InputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.security.cert.X509Certificate;
import java.util.Map;

public class FxHttp {
    private HttpClient client;

    public FxHttp() {
        try {
            client = HttpClient.newBuilder()
                    .sslContext(SSLContext.getDefault())
                    .followRedirects(HttpClient.Redirect.ALWAYS)
                    .build();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private HttpRequest.Builder newReq() {
        return HttpRequest.newBuilder()
                .header("User-Agent",
                        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg");
    }

    public String upload(String url, Map<String, Object> params, HttpFile... files) {
        MultiPartBodyPublisher publisher = new MultiPartBodyPublisher();

        if (params != null && !params.isEmpty()) {
            for (var k : params.keySet()) {
                var v = params.get(k);
                if (v != null) {
                    publisher.addPart(k, v.toString());
                }
            }
        }
        for (var file : files) {
            publisher.addPart(file.paramName, () -> file.fileStream, file.fileName, file.contentType);
        }
        try {
            var req = newReq()
                    .uri(URI.create(url))
                    .header("Content-Type", "multipart/form-data; boundary=" + publisher.getBoundary())
                    .POST(publisher.build());
            var resp = client.send(req.build(), HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
            if (resp.statusCode() == 200) {
                return resp.body();
            } else {
                throw new ResponseException(resp.statusCode());
            }
        } catch (Exception e) {
            throw ExUtil.toRuntime(e);
        }
    }

    public String post(String url, Map<String, Object> params) {
        return post(url, params, null);
    }

    public String post(String url, Map<String, Object> params, Action1T<HttpRequest.Builder> set) {
        var body = params != null ? UrlUtil.join(params) : "";
        return post(url, body, set);
    }

    public String post(String url, String body) {
        return post(url, body, null);
    }

    public String post(String url, String body, Action1T<HttpRequest.Builder> set) {
        if (body == null) {
            body = "";
        }
        var req = newReq().uri(URI.create(url));
        if (body.startsWith("{")) {
            req.header("Content-Type", "application/json;charset=utf-8");
        } else {
            req.header("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
        }
        req.POST(HttpRequest.BodyPublishers.ofString(body));
        if (set != null) {
            set.execute(req);
        }
        try {
            var resp = client.send(req.build(), HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
            if (resp.statusCode() == 200) {
                return resp.body();
            } else {
                throw new ResponseException(resp.statusCode());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public String get(String url) {
        return get(url, null, null);
    }

    public String get(String url, Action1T<HttpRequest.Builder> set) {
        return get(url, null, set);
    }

    public String get(String url, Map<String, Object> params) {
        return get(url, params, null);
    }

    public String get(String url, Map<String, Object> urlParams, Action1T<HttpRequest.Builder> set) {
        if (urlParams != null && !urlParams.isEmpty()) {
            url = UrlUtil.join(url, urlParams);
        }
        var req = newReq().uri(URI.create(url)).GET();
        if (set != null) {
            set.execute(req);
        }
        try {
            var resp = client.send(req.build(), HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
            if (resp.statusCode() == 200) {
                return resp.body();
            } else {
                throw new ResponseException(resp.statusCode());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        var http = new FxHttp();
        var rs = http.get("https://blog.csdn.net/sdawdawdawfafa", null, null);
        System.out.println(rs);
    }

    public static class HttpFile {
        public String paramName;
        public String fileName;
        public String contentType;
        public InputStream fileStream;

        public static HttpFile setNew(Action1T<HttpFile> action) {
            HttpFile file = new HttpFile();
            action.execute(file);
            return file;
        }
    }

    public static class ResponseException extends RuntimeException {
        private int code;

        public int getResponseCode() {
            return code;
        }

        public ResponseException(int code) {
            super("response status code: " + code);
            this.code = code;
        }
    }

    private static class DefaultTrustManager implements X509TrustManager {

        @Override
        public void checkClientTrusted(X509Certificate[] arg0, String arg1) {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1) {
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    }
}
